package cn.jilian.data.util;

import java.lang.reflect.Array;
import java.sql.Types;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;

import com.fasterxml.jackson.databind.ObjectMapper;

public class DataConverter {

	private static String[] dtPatterns = new String[]{"yyyy-MM-dd'T'HH:mm:ss","yyyy-MM-dd HH:mm:ss","yyyy-MM-dd","HH:mm:ss"};//@see JSONUtil.RFC3339_FORMAT

	private static Object getDate(Object str){
		//Date v = new java.sql.Date(0);//if null, pgsql will error by null serial as bytea
		Object v =null;; //new TimestampType() @see QueryDAO.setParameter
		try { 
			 v = DateUtils.parseDate(str.toString(),dtPatterns);
		}catch (Exception e) {
		}
		return v;
	}
	
	private static Object getLong(Object str){
		Object v =  0;//new LongType()
		try {
		//v=NumberUtils.toLong(str.toString());//default 0;
		  v = Long.parseLong(str.toString());
        } catch (Exception nfe) {
        }
		return v;
	}
	
	private static Object getInteger(Object str){
		Object v =0;// Hibernate.INTEGER; new IntegerType()
		try {
		  v = Integer.parseInt(str.toString());
        } catch (Exception nfe) {
        }
		return v;
	}
	
	private static Object getFloat(Object str){
		Object v =  0.0f;//newFloatType; Hibernate.FLOAT;
		try {
		  v = Float.parseFloat(str.toString());
        } catch (Exception nfe) {
        }
		return v;
	}
	
	private static Object getDouble(Object str){
		Object v = 0.0;//new DoubleType(); Hibernate.DOUBLE;
		try {
		  v = Double.parseDouble(str.toString());
        } catch (Exception nfe) {
        }
		return v;
	}
	
	public static Object convert(Object value,int dataType){
		/**
		 * java.sql.Types: BIT=-7 TINYINT=-6(8b) BIGINT=-5(64b) NULL=0 CHAR=1 NUMERIC=2 DECIMAL=3 INTEGER=4(32b) SMALLINT=5(16b) FLOAT=6(32b) REAL=7 DOUBLE=8(64b) VARCHAR=12 BOOLEAN=16
		 * DATE =91 TIME=92 TIMESTAMP=93 OTHER=1111 JAVA_OBJECT=2000 ARRAY=2003 BLOB=2004 CLOB=2005 SQLXML=2009
		 */

		if(value==null)return null;
		switch(dataType){
			case Types.NULL://0 default as long;
			case Types.BIGINT:
				value = getLong(value);
			break;
			case Types.BIT:
			case Types.TINYINT:
			case Types.SMALLINT:
			case Types.INTEGER:
				value = getInteger(value);
				break;
			case Types.NUMERIC:
			case Types.DECIMAL:
				value = (String.valueOf(value).indexOf('.')>-1)?getDouble(value):getLong(value);
				break;
			case Types.FLOAT:
				value = getFloat(value);
				break;
			case Types.REF:
				break;
			case Types.REAL:
			case Types.DOUBLE:
				value = getDouble(value);
				break;
			case Types.ARRAY:
				if(String.class.isAssignableFrom(value.getClass())) {
					String list=(String)value;
					if(StringUtils.startsWith(list, "[")&&StringUtils.endsWith(list, "]")) {
						value=objectMapper.convertValue(list, Array.class);
					}else {
						value=StringUtils.split(list, ",");
					}
				}
			case Types.JAVA_OBJECT:
				if(String.class.isAssignableFrom(value.getClass())) {
					String text=(String)value;
					if(StringUtils.startsWith(text, "{")
					&&StringUtils.endsWith(text, "}")) {
						value=objectMapper.convertValue(text, Map.class);
						break;
					}
				}else {
					return value;
				}
			case Types.BOOLEAN:
				if(String.class.isAssignableFrom(value.getClass())) {
					return StringUtils.equalsIgnoreCase("true", (String)value);
				}else if(Number.class.isAssignableFrom(value.getClass())) {
					Number v=(Number)value;
					return v.longValue()>0;
				}else {
					return Boolean.TRUE;
				}
			case Types.DATE:
			case Types.TIME:
			case Types.TIMESTAMP:
				value = getDate(value);
				break;
			default: 
		}
		
		return value;
	}

	public static final ObjectMapper objectMapper=new ObjectMapper();
	
}
